#ifndef FREQUENCY_H
#define	FREQUENCY_H

//#include <cstdlib>
#include <iostream>
#include <iomanip> // for setw, left, right
#include <map>
#include <float.h> // for min/max values (DBL_MAX)
#include <vector>
#include <assert.h>

// For r-squared.
#include<cmath>

#define ERR_NOT_SETUP "ERROR: Data and/or bins not setup. Use setData and setBins to do this"
#define ERR_DATA_VECTOR_NOT_SETUP "Data vector not setup. Use setData or addValue to do this"
#define ERR_FREQ_BINS_NOT_SETUP "Frequency bins (map) not setup. Use setBins or addValue to do this"
#define ERR_DATA_INDEX_OUTSIDE_RANGE "Cannot getSample: index outside range "
#define ERR_BIN_NOT_FOUND "Bin was not found in Frequency table"
/**
 *
 * @file:   Frequency.h
 * @author: justin
 *
 * @description A basic frequency distribution object.
 * To use, create a Frequency object with range and bucket size
 * then use the add function to count frequencies in the right buckets.
 * Includes some basic stats: min, max, average and std deviation.
 * Does not use boost stats at the moment - can be updated.
 * Includes less than minimum and greater than maximum buckets to values
 * outside the defined range.
 *
 * @date Created on June 2, 2012, 5:04 PM*
 */
class Frequency {
public:
	/**
	 * \brief Frequency constructor, no parameters.
	 * Creates a Frequency object, ready for setBins and setData (in that order)
	 */
	Frequency(void);
	/**
	 * \brief Set up frequency bins
	 * Frequency constructor sets up frequency table with bins
	 * starting at 'start' and ending at 'end' with a defined bin size
	 * eg. setBins(0,100,20) creates 5 bins (0,20,40,60,80,100) plus two bins
	 * for low- and high-vals (- infinity, + infinity).
     * @param start Lowest first bucket eg. 0
     * @param end   Highest defined bucket eg. 100
     * @param bucketSize Size of each bin eg. 20
	 * @see setBinsFlag
     */
	void SetBins(double start, double end, double binSize);
	/**
	 * \brief Set the base dataset
     * @param parmData A std::vector<double> of data values.
     */
	void SetData(std::vector<double>& parmData);
	/**
	 * \brief Insert a single sample value into data vector.
	 * Insert a sample and increment appropriate bin in range in bin vector
	 * (mapFreq).
     * @param addVal A number to be added to data vector, and processed as a
	 *               frequency entry in the frequency map.
     */
	void AddSample(double addVal);
	/**
	 * \brief Copy constructor (not implemented).
	 * Copy constructor. Takes reference.
     * @param orig
     */
	Frequency(const Frequency& orig);
	/**
	 * \brief Frequency destructor
	 * Virtual destructor. Defined as virtual so any subclasses (not used)
	 * have their correct subclass destructor method called.
	 * Note in C++, superclass (ie. this) destructors are called first, followed
	 * by any subclasses that derive from this class.
     */
	virtual ~Frequency();

	/**
	 * Dump a list of bins.
     */
	void DumpBins(void);
	/**
	 * Get a vector of the bins
     * @return A vector of bins
     */
	std::vector<double>* GetBinsPtr(void);
	std::vector<double> GetBins(void);
/**
 * Get the frequency at a specified bin value
 * @param bin	The bin for which you want the frequency returned
 * @return		The frequency value in this bin.
 */
	double GetFrequencyAtBin(double bin);

	/**
	 * \brief Dump contents of frequency bins.
	 * Lists frequency content as bin -tab- frequency.
	 * Simply print of contents of frequency bins.
     */
	void Dump(void);
	/**
	 * \brief Get a vector containing the frequency table.
	 * Obtain the frequency map for this dataset and bins.
     * @return A vector of double, double containing ranges and frequencies.
     */
	std::map<double,double>& GetFrequencyTable(void);
	/**
	 * \brief Number of samples
	 * Return number of samples in this frequency object ie. a weighted sum.
	 */
	int N(void);
	/**
	 * \brief Print a basic tree graph
	 * Print a basic tree graph of distribution. Uses '*' characters to
	 * represent frequency units. Automatically calculates and applies scale
	 * so tree diagram fits in 80 columns.
	 */
	void PrintTree(void);
	/**
	 * Clear out this object to start with new parameters.
	 * Empties all containers: vecDump and mapFreq.
	 */
	void Reset(void);
	/**
	 * \brief Calculate the average of the data set.
	 * Processes data vector to obtain average for this dataset.
     * @return The average of the samples in data.
     */
	double Average(void);
	/**
	 * \brief Calculate the standard deviation (sample, not population).
	 * Formula used is square root of sum of squared differences divided by
	 * sample size -1 ie. for sampled set, not population.
     * @return The sample standard deviation.
     */
	double StdDev(void);
	/**
	 * Return the sum of values in sample data.
	 */
	double Sum(void);

	/**
	 * Retrieve a sample
	 * Get sample at [index].
     * @param index The position of the sample data you want
     * @return The value of the sample data at this index.
     */
	double GetSample(int index);
	/**
	 * \brief Retrieve maximum value in data
	 * Returns the largest value in the sample data. Set up is via
	 * addVals which maintains max and min values seen
     * @return The largest value in the sample
	 * @see addValues()
     */
	double Max(void);
	/**
	 * \brief Retrieve minimum value in data
	 * Returns the smallest value in the sample data. Set up is via
	 * addVals which maintains max and min values seen
     * @return The smallest value in the sample
	 * @see addValues()
     */
	double Min(void);
	/**
	 * \brief Reset/empty data
	 * Reset the data vector, but use existing bins.
	 */
	void ResetData(void);
	/**
	 * \brief Round a number (double) to 'places' decimal places.
	 * Does not deal with internal representation of doubles as eg. -1.899999
     * @param x The number to round
     * @param places The number of decimal places to round the number to.
     * @return
     */
	double _round3(double x, int places);
	double _round2(double x, int places);
	double _round(const double& x, const int& numDecimals);
private:
	/**
	 * \brief Map containing buckets and frequency counts.
	 * C++ uses a map object which is made up of 'pairs'
	 * In our case, the first entry is the bucket title and represents
	 * the beginning value of the bucket eg. 20 is for values >=20 and less than
	 * next bucket (20 + bucket size).
	 */
	std::map<double,double> _mapFreq;
	/**
	 * \brief An iterator to go through the frequency bin map.
	 */
	std::map<double,double>::iterator _itMap;
	/**
	 * \brief Data vector containing sample values
	 */
	std::vector<double> _vecData;
	/**
	 * \brief Frequency map iterator
	 * An iterator to go through the frequency bin map.
	 */
	std::vector<double>::iterator _itData;
	/**
	 * \brief Z-score map for Q-Q plot analysis
	 * Ranked z% and z-score map for normal distribution checking.
	 */
	std::map<double,double> _rankedZMap;
	/**
	 * Private properties of bucket - minimum, maximum bucket and size of buckets
	 */
	double _start, _end, _binSize;
	/**
	 * Setup flags: checked to make sure data was loaded and bins are ready
	 * before any reporting gets done.
	 */
	bool _setupFlag;
	/**
	 * \brief Set up data flag
	 * True represents data vector has been loaded
	 */
	bool _setupDataFlag;

	/**
	 * \brief Set up bins flag
	 * True represents bins have been created for this frequency object
	 */
	bool _setupBinsFlag;
	/**
	 * Debug mode prints a few extra statistics.
	 */
	bool _debugMode;
	/**
	 * \brief Allocate a sample to a frequency bin.
	 * Uses hi/lo-val bins outside bin range. Sample is added to internal
	 * vector (vecData). This is first step in using Frequency.
     * @param addVal
     */
	void _allocateBin(double addVal);
	double _dataMax;
	double _dataMin;

};

#endif	/* FREQUENCY_H */

